import { Result } from '@/typings/axios.d';
import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
import { API, HOST } from '@/config';
import router from "@/router";
import { useUserStoreWithOut } from '@/store/modules/user';
import { message } from 'ant-design-vue';



// axios默认配置
Object.assign(axios.defaults, {
  headers: {
    common: {},
    'Content-Type': 'application/json',
  },
  timeout: 20000,
});

//不需要带请求头
const noToken: any = [ 'auth/captcha', 'auth/login'];
const outCodes :any = ['SYS-001-406', 'SYS-001-407']; //退出code

/**
 * 请求前的参数处理
 *
 * @class Methods
 */
interface IMethods {
  /**
   * 基类
   * 请求的公共方法
   * @param {string} url 接口的标识
   * @returns {string} 实际接口地址
   * @memberof IMethods
   */
  getUrl(url: string): string;
}

class Methods implements IMethods {
  static instance; //单例
  static getInstance<T= any>() {
    if (!this.instance) {
      this.instance = new this();
    }
    return this.instance;
  }

  getUrl(url: string) {
    let backendDetail: any = null;
    //获取服务信息
    API.forEach((item: any) => {
      backendDetail = item.interfaces.indexOf(url) != -1 ? item : backendDetail;
    });
    return (
      url?.indexOf('http') == 0 ? url :
      backendDetail ? (backendDetail.test ? backendDetail.testUrl : HOST) + ((backendDetail.service ? '/' + backendDetail.service + '/' : '/') + url) : HOST +  (url.charAt(0) === "/" ? url: '/' + url)
    );
  }
}

export interface IHttp extends IMethods {
  /**
   *api方式请求
   *
   * @param {string} url
   * @param {any} data get、delete用的是params，post跟put用的是data
   * @param {String} method post、get、delete、put模式
   * @param {Object} headers 头部信息的配置，但是上传图片就写死了
   * @param {boolean} urlParema 为true时参数带在URL上
   * @returns {Promise<T>}
   * @memberof IHttp
   */
  api<T = any>(url: string, data: any, method: String, urlParema?: boolean, urlName?: any, httpOpt?:any): Promise<T>;
}

class Http extends Methods implements IHttp {
  api<T = any>(url: string, data: any, method: String, urlParema: boolean = false, urlName: any = '', httpOpt:any = {}, timeout:number = 20000): Promise<T> {
    //表示该接口正在调用
    let httpOpts: any = Object.assign({
      url: super.getUrl(url),
      method: method,
    }, httpOpt) ;

    if( typeof data === 'string' || typeof data === 'number' ){
      httpOpts.url += '/' + data;
    }
    if( typeof urlName === 'object' ){
      let params = '';
      let keys = Object.keys(urlName);
      keys.forEach((name,index)=>{
        if( urlName[name] ){
          params += name + '=' + urlName[name] + ( index == keys.length-1 ?"":"&" );
        }
      })
      httpOpts.url += '?' + params;
    }else{
      if( urlName ){
        httpOpts.url += '/' + urlName;
      }
    }

    //post跟get的参数判断
    if (urlParema || method === 'post-url') {
      httpOpts.params = data;
      httpOpts.noToken = noToken.indexOf(url) !== -1 ? true : false; //不需要头部token信息
    } else if (method === 'post') {
      httpOpts.data = data;
  
    } else if (method === 'get') {
      if( typeof data === 'object' ){
        httpOpts.params = data;
      }
    } else if (method === 'delete') {
      httpOpts.params = data;//这里的删除接口
    }else if (method === 'delete-data') {
      httpOpts.method = 'delete';
      httpOpts.data = data;//这里的删除接口
    } else if (method === 'delete-form') {
      httpOpts.method = 'delete';
      httpOpts.headers = {
        'Content-Type': 'application/x-www-form-urlencoded',
      };
      let str= '';
      for (const key in data) {
        if (Object.prototype.hasOwnProperty.call(data, key)) {
          str += (key + '='+ data[key] ) + '&'
        }
      }
      httpOpts.data = str;
    } else if (method === 'put') {
      httpOpts.data = data;
    }else if (method === 'post-form') {
      httpOpts.method = 'post';
      httpOpts.headers = {
        'Content-Type': 'application/x-www-form-urlencoded',
      };
      let str= '';
      for (const key in data) {
        if (Object.prototype.hasOwnProperty.call(data, key)) {
          str += (key + '='+ data[key] ) + '&'
        }
      }
      httpOpts.data = str;
    }else if( method === 'form-data' ){
      httpOpts.method = 'post';
      httpOpts.data = data;
      httpOpts.headers = {
        'Content-Type': 'multipart/form-data',
      };
    }

    //上传图片
    if (url === 'Upload/UploadFile' || url === 'File/UploadVideo' ) {
      httpOpts.headers = {
        'Content-Type': 'multipart/form-data',
      };
    }
    return new Promise(function (resolve, reject) {
        axios({
          ...httpOpts,
          timeout
        })
        .then((res: AxiosResponse<Result>) => {
          resolve(res as unknown as Promise<T>);
        })
        .catch((error) => {
          if( error.code === "ECONNABORTED" ){
            message.error('接口超时了')
          }
          reject(error);
        });
    });
  }
}

// request拦截器
axios.interceptors.request.use(
  function (config: any) {
    const userStore = useUserStoreWithOut();
    let accessToken: any = userStore.getToken;
    let isToken: boolean = false;
    noToken.forEach((name: string) => {
      if (config.url.indexOf(name) !== -1) {
        isToken = true;
      }
    });
    if (accessToken && !config.noToken && !isToken) {
      // 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
      config.headers['token'] =  accessToken;
    }
    return config;
  }, (error)=> {
    const userStore = useUserStoreWithOut();
    userStore.logout();
    return Promise.reject(error);
  }
);
// response拦截器
axios.interceptors.response.use(
  (response) => {
    if (!response) return;
    if (response.status === 200) {
      //退出登录
      if( outCodes.includes(response.data.code)  ){
        const userStore = useUserStoreWithOut();
        userStore.logout();
      }else if( response.data.success === false ){
        message.error(response.data.message)
        return response.data
      }
      return response.data;
    } else if(response.status === 204) {
      return response.config.method !== 'get' ? true : null;
    } else {
      if( typeof response === 'object' ){
        if( response.data ){
          message.error(response.data.message || response.data.error)
        }else{
          return response
        }
      }
    }
  },
  (error) => {
    if (error.response) {
      switch (error.response.status) {
        case 401:
        case 406:
        case 407:
          const userStore = useUserStoreWithOut();
          userStore.logout();
          break;
        case 403:
          
        default:
          if( error.response.data ){
            message.destroy();
            message.error(error.response.data.error?.message ? error.response.data.error.message : error.response.error)
          }
      }
    }
    return Promise.reject(error);
  }
);

export const $Http = Http.getInstance();

